#ifndef __CASE_TASK_EXECUTOR_H__
#define __CASE_TASK_EXECUTOR_H__

#include <iostream>
#include <gtest/gtest.h>
#include "basic/types.h"
#include "basic/task_executor.h"

using namespace basic;

class TaskA : public task_executor::Task
{
  public:
    TaskA() = delete;
    TaskA(int n)
        : N(n)
    {
    }
    ~TaskA() = default;
    void Execute() override
    {
        m_nSum = 0;
        while (N > 0)
        {
            m_nSum += N;
            --N;
        }
    }

    int GetSum() const
    {
        return m_nSum;
    }

  private:
    int N{0};
    int m_nSum{0};
};

TEST(Test_task_executor, construtor_destroctor)
{
    task_executor::TaskExecutor te(1);
    task_executor::TaskExecutor te2(2);
    task_executor::TaskExecutor te3(3);
    task_executor::TaskExecutor te4(4);
}

TEST(Test_task_executor, AddTask)
{
    task_executor::TaskExecutor te(1);
    TaskA a(10000);
    te.AddTask(&a);
    while (a.GetStatus() != task_executor::ETaskStatus::FINISHED_EXECUTING)
    {
    }
    ASSERT_EQ(a.GetSum(), 50005000);
}

TEST(Test_task_executor, RemoveTask)
{
    task_executor::TaskExecutor te(1);
    TaskA t1(10000),t2(10000),t3(10000);
    te.AddTask(&t1);
    te.AddTask(&t2);
    te.AddTask(&t3);
    ASSERT_EQ(te.RemoveTask(&t2),true);
    ASSERT_EQ(te.RemoveTask(&t3),true);

    while (t1.GetStatus() != task_executor::ETaskStatus::FINISHED_EXECUTING)
    {
    }
    ASSERT_EQ(t1.GetSum(), 50005000);
}

TEST(Test_task_executor, executorManyWith1Thread)
{
    int N = 1000;
    task_executor::TaskExecutor te(1);
    std::vector<TaskA*> vecSwap2;
    std::vector<TaskA*> vecSwap1;
    for (int i = 0; i < N; ++i)
    {
        vecSwap1.push_back(new TaskA(10000));
    }
    for (auto& it : vecSwap1)
    {
        te.AddTask(it);
    }

    std::vector<TaskA*>& vecCurrent = vecSwap1;
    std::vector<TaskA*>& vecNext = vecSwap2;
    int j = 0;
    while (N > 0)
    {
        vecNext.clear();
        for (auto& it : vecCurrent)
        {
            TaskA* pT = it;
            if (pT->GetStatus() == task_executor::ETaskStatus::FINISHED_EXECUTING)
            {
                ASSERT_EQ(pT->GetSum(), 50005000);
                delete pT;
                --N;
            }
            else
            {
                vecNext.push_back(pT);
            }
        }
        ++j;
        vecCurrent = vecNext;
        vecNext = j % 2 == 1 ? vecSwap1 : vecSwap2;
    }
}

TEST(Test_task_executor, executorManyWith10Thread)
{
    int N = 1000;
    task_executor::TaskExecutor te(10);
    std::vector<TaskA*> vecSwap2;
    std::vector<TaskA*> vecSwap1;
    for (int i = 0; i < N; ++i)
    {
        vecSwap1.push_back(new TaskA(10000));
    }
    for (auto& it : vecSwap1)
    {
        te.AddTask(it);
    }

    std::vector<TaskA*>& vecCurrent = vecSwap1;
    std::vector<TaskA*>& vecNext = vecSwap2;
    int j = 0;
    while (N > 0)
    {
        vecNext.clear();
        for (auto& it : vecCurrent)
        {
            TaskA* pT = it;
            if (pT->GetStatus() == task_executor::ETaskStatus::FINISHED_EXECUTING)
            {
                ASSERT_EQ(pT->GetSum(), 50005000);
                delete pT;
                --N;
            }
            else
            {
                vecNext.push_back(pT);
            }
        }
        ++j;
        vecCurrent = vecNext;
        vecNext = j % 2 == 1 ? vecSwap1 : vecSwap2;
    }
}

#endif
